home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Graphics / Ghostscript / source / gdevwpr2.c < prev    next >
C/C++ Source or Header  |  1997-05-09  |  21KB  |  739 lines

  1. /* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevwpr2.c */
  20. /*
  21.  * Microsoft Windows 3.n printer driver for Ghostscript.
  22.  * Original version by Russell Lang and
  23.  * L. Peter Deutsch, Aladdin Enterprises.
  24.  * Modified by rjl 1995-03-29 to use BMP printer code
  25.  */
  26.  
  27. /* This driver uses the printer default size and resolution and
  28.  * ignores page size and resolution set using -gWIDTHxHEIGHT and
  29.  * -rXxY.  You must still set the correct PageSize to get the
  30.  * correct clipping path
  31.  */
  32.  
  33. #include "gdevprn.h"
  34. #include "gdevpccm.h"
  35.  
  36. #include "windows_.h"
  37. #include <shellapi.h>
  38. #include "gp_mswin.h"
  39.  
  40. #include "gp.h"
  41. #include "commdlg.h"
  42.  
  43.  
  44. /* Make sure we cast to the correct structure type. */
  45. typedef struct gx_device_win_pr2_s gx_device_win_pr2;
  46. #undef wdev
  47. #define wdev ((gx_device_win_pr2 *)dev)
  48.  
  49. /* Device procedures */
  50.  
  51. /* See gxdevice.h for the definitions of the procedures. */
  52. private dev_proc_open_device(win_pr2_open);
  53. private dev_proc_close_device(win_pr2_close);
  54. private dev_proc_print_page(win_pr2_print_page);
  55. private dev_proc_map_rgb_color(win_pr2_map_rgb_color);
  56. private dev_proc_map_color_rgb(win_pr2_map_color_rgb);
  57. private dev_proc_put_params(win_pr2_put_params);
  58.  
  59. private void win_pr2_set_bpp(gx_device *dev, int depth);
  60.  
  61. private gx_device_procs win_pr2_procs =
  62.   prn_color_params_procs(win_pr2_open, gdev_prn_output_page, win_pr2_close,
  63.    win_pr2_map_rgb_color, win_pr2_map_color_rgb, 
  64.    gdev_prn_get_params, win_pr2_put_params);
  65.  
  66.  
  67. /* The device descriptor */
  68. typedef struct gx_device_win_pr2_s gx_device_win_pr2;
  69. struct gx_device_win_pr2_s {
  70.     gx_device_common;
  71.     gx_prn_device_common;
  72.     HDC hdcprn;
  73.     DLGPROC lpfnAbortProc;
  74.     DLGPROC lpfnCancelProc;
  75. };
  76.  
  77. gx_device_win_pr2 far_data gs_mswinpr2_device = {
  78.   prn_device_std_body(gx_device_win_pr2, win_pr2_procs, "mswinpr2",
  79.   DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72.0, 72.0,
  80.   0, 0, 0, 0,
  81.   0, win_pr2_print_page), /* depth = 0 */
  82.   0,    /* hdcprn */
  83.   NULL    /* lpfnAbortProc */
  84. };
  85.  
  86. private int win_pr2_getdc(gx_device_win_pr2 *);
  87.  
  88. /* Open the win_pr2 driver */
  89. private int
  90. win_pr2_open(gx_device *dev)
  91. {    int code;
  92.     int depth;
  93.     PRINTDLG pd;
  94.     POINT offset;
  95.     POINT size;
  96.     float m[4];
  97.     FILE *pfile;
  98.  
  99.     if (hDlgModeless) {
  100.         /* device cannot opened twice since only one hDlgModeless */
  101.         return gs_error_limitcheck;
  102.     }
  103.  
  104.     /* get a HDC for the printer */
  105.         if (!win_pr2_getdc(wdev)) {
  106.         /* couldn't get a printer from -sOutputFile= */
  107.         /* Prompt with dialog box */
  108.         memset(&pd, 0, sizeof(pd));
  109.         pd.lStructSize = sizeof(pd);
  110.         pd.hwndOwner = hwndtext;
  111.         pd.Flags = PD_PRINTSETUP | PD_RETURNDC;
  112.         if (!PrintDlg(&pd)) {
  113.         /* device not opened - exit ghostscript */
  114.             return gs_error_Fatal;    /* exit Ghostscript cleanly */
  115.         }
  116.         GlobalFree(pd.hDevMode);
  117.         GlobalFree(pd.hDevNames);
  118.         pd.hDevMode = pd.hDevNames = NULL;
  119.         wdev->hdcprn = pd.hDC;
  120.     }
  121.     if (!(GetDeviceCaps(wdev->hdcprn, RASTERCAPS) != RC_DIBTODEV)) {
  122.         fprintf(stderr, "Windows printer does not have RC_DIBTODEV\n");
  123.         DeleteDC(wdev->hdcprn);
  124.         return gs_error_limitcheck;
  125.     }
  126.  
  127.     /* initialise printer, install abort proc */
  128. #ifdef __WIN32__
  129.     wdev->lpfnAbortProc = (DLGPROC)AbortProc;
  130. #else
  131. #ifdef __DLL__
  132.     wdev->lpfnAbortProc = (DLGPROC)GetProcAddress(phInstance, "AbortProc");
  133. #else
  134.     wdev->lpfnAbortProc = (DLGPROC)MakeProcInstance((FARPROC)AbortProc,phInstance);
  135. #endif
  136. #endif
  137.     Escape(wdev->hdcprn,SETABORTPROC,0,(LPSTR)wdev->lpfnAbortProc,NULL);  
  138.     if (Escape(wdev->hdcprn, STARTDOC, lstrlen(szAppName), szAppName, NULL) <= 0) {
  139. #if !defined(__WIN32__) && !defined(__DLL__)
  140.         FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
  141. #endif
  142.         DeleteDC(wdev->hdcprn);
  143.         return gs_error_limitcheck;
  144.     }
  145.  
  146.     dev->x_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSX);
  147.     dev->y_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSY);
  148.     Escape(wdev->hdcprn, GETPHYSPAGESIZE, 0, NULL, (LPPOINT)&size);
  149.     gx_device_set_width_height(dev, (int)size.x, (int)size.y);
  150.     Escape(wdev->hdcprn, GETPRINTINGOFFSET, 0, NULL, (LPPOINT)&offset);
  151.     /* m[] gives margins in inches */
  152.     m[0] /*left*/ = offset.x / dev->x_pixels_per_inch;
  153.     m[3] /*top*/ = offset.y / dev->y_pixels_per_inch;
  154.     m[2] /*right*/ =
  155.         (size.x - offset.x - GetDeviceCaps(wdev->hdcprn, HORZRES))
  156.          / dev->x_pixels_per_inch;
  157.     m[1] /*bottom*/ =
  158.         (size.y - offset.y - GetDeviceCaps(wdev->hdcprn, VERTRES))
  159.          / dev->y_pixels_per_inch
  160.         + 0.15;  /* hack to add a bit more margin for deskjet printer */
  161.     gx_device_set_margins(dev, m, true);
  162.  
  163.     depth = dev->color_info.depth;
  164.     if (depth == 0) {
  165.         /* Set parameters that were unknown before opening device */
  166.         /* Find out if the device supports color */
  167.         /* We recognize 1, 4 (but uses only 3), 8 and 24 bit color devices */
  168.         depth = GetDeviceCaps(wdev->hdcprn,PLANES) * GetDeviceCaps(wdev->hdcprn,BITSPIXEL);
  169.     }
  170.     win_pr2_set_bpp(dev, depth);
  171.  
  172.     /* gdev_prn_open opens a temporary file which we don't want */
  173.     /* so we specify the name now so we can delete it later */
  174.     pfile = gp_open_scratch_file(gp_scratch_file_name_prefix, 
  175.         wdev->fname, "wb");
  176.     fclose(pfile);
  177.     code = gdev_prn_open(dev);
  178.     /* delete unwanted temporary file */
  179.     unlink(wdev->fname);
  180.  
  181.     /* inform user of progress with dialog box and allow cancel */
  182. #ifdef __WIN32__
  183.     wdev->lpfnCancelProc = (DLGPROC)CancelDlgProc;
  184. #else
  185. #ifdef __DLL__
  186.     wdev->lpfnCancelProc = (DLGPROC)GetProcAddress(phInstance, "CancelDlgProc");
  187. #else
  188.     wdev->lpfnCancelProc = (DLGPROC)MakeProcInstance((FARPROC)CancelDlgProc, phInstance);
  189. #endif
  190. #endif
  191.     hDlgModeless = CreateDialog(phInstance, "CancelDlgBox", hwndtext, wdev->lpfnCancelProc);
  192.     ShowWindow(hDlgModeless, SW_HIDE);
  193.  
  194.     return code;
  195. };
  196.  
  197. /* Close the win_pr2 driver */
  198. private int
  199. win_pr2_close(gx_device *dev)
  200. {    int code;
  201.     int aborted = FALSE;
  202.     /* Free resources */
  203.  
  204.     if (!hDlgModeless)
  205.         aborted = TRUE;
  206.     else
  207.         DestroyWindow(hDlgModeless);
  208.     hDlgModeless = 0;
  209. #if !defined(__WIN32__) && !defined(__DLL__)
  210.     FreeProcInstance((FARPROC)wdev->lpfnCancelProc);
  211. #endif
  212.  
  213.     if (aborted)
  214.         Escape(wdev->hdcprn,ABORTDOC,0,NULL,NULL);
  215.     else
  216.         Escape(wdev->hdcprn,ENDDOC,0,NULL,NULL);
  217.  
  218. #if !defined(__WIN32__) && !defined(__DLL__)
  219.     FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
  220. #endif
  221.     DeleteDC(wdev->hdcprn);
  222.     code = gdev_prn_close(dev);
  223.     return code;
  224. }
  225.  
  226.  
  227. /* ------ Internal routines ------ */
  228.  
  229. #undef wdev
  230. #define wdev ((gx_device_win_pr2 *)pdev)
  231.  
  232. /************************************************/
  233.  
  234.  
  235. /* ------ Private definitions ------ */
  236.  
  237.  
  238. /* new win_pr2_print_page routine */
  239.  
  240. /* Write BMP header to memory, then send bitmap to printer */
  241. /* one scan line at a time */
  242. private int
  243. win_pr2_print_page(gx_device_printer *pdev, FILE *file)
  244. {    int raster = gdev_prn_raster(pdev);
  245.     /* BMP scan lines are padded to 32 bits. */
  246.     ulong bmp_raster = raster + (-raster & 3);
  247.     ulong bmp_raster_multi;
  248.     int scan_lines, yslice, lines, i;
  249.     int width;
  250.     int depth = pdev->color_info.depth;
  251.     byte *row;
  252.     int y;
  253.     int code = 0;            /* return code */
  254.     MSG msg;
  255.     char dlgtext[32];
  256.     HGLOBAL hrow;
  257.  
  258.     struct bmi_s {
  259.         BITMAPINFOHEADER h;
  260.         RGBQUAD pal[256];
  261.     } bmi;
  262.  
  263.     scan_lines = dev_print_scan_lines(pdev);
  264.     width = pdev->width - ((dev_l_margin(pdev) + dev_r_margin(pdev) -
  265.         dev_x_offset(pdev)) * pdev->x_pixels_per_inch);
  266.  
  267.     yslice = 65535 / bmp_raster;    /* max lines in 64k */
  268.     bmp_raster_multi = bmp_raster * yslice;
  269.     hrow = GlobalAlloc(0, bmp_raster_multi);
  270.     row = GlobalLock(hrow);
  271.     if ( row == 0 )            /* can't allocate row buffer */
  272.         return_error(gs_error_VMerror);
  273.  
  274.     /* Write the info header. */
  275.  
  276.     bmi.h.biSize = sizeof(bmi.h);
  277.     bmi.h.biWidth = pdev->width;  /* wdev->mdev.width; */
  278.     bmi.h.biHeight = yslice;
  279.     bmi.h.biPlanes = 1;
  280.     bmi.h.biBitCount = pdev->color_info.depth;
  281.     bmi.h.biCompression = 0;
  282.     bmi.h.biSizeImage = 0;            /* default */
  283.     bmi.h.biXPelsPerMeter = 0;        /* default */
  284.     bmi.h.biYPelsPerMeter = 0;        /* default */
  285.  
  286.     /* Write the palette. */
  287.  
  288.     if ( depth <= 8 )
  289.     {    int i;
  290.         gx_color_value rgb[3];
  291.         LPRGBQUAD pq;
  292.         bmi.h.biClrUsed = 1 << depth;
  293.         bmi.h.biClrImportant = 1 << depth;
  294.         for ( i = 0; i != 1 << depth; i++ )
  295.         {    (*dev_proc(pdev, map_color_rgb))((gx_device *)pdev,
  296.                 (gx_color_index)i, rgb);
  297.             pq = &bmi.pal[i];
  298.             pq->rgbRed   = gx_color_value_to_byte(rgb[0]);
  299.             pq->rgbGreen = gx_color_value_to_byte(rgb[1]);
  300.             pq->rgbBlue  = gx_color_value_to_byte(rgb[2]);
  301.             pq->rgbReserved = 0;
  302.         }
  303.     }
  304.     else {
  305.         bmi.h.biClrUsed = 0;
  306.         bmi.h.biClrImportant = 0;
  307.     }
  308.  
  309.     sprintf(dlgtext, "Printing page %d", (int)(pdev->PageCount)+1);
  310.     SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PRINTING), dlgtext);
  311.     ShowWindow(hDlgModeless, SW_SHOW);
  312.  
  313.     for ( y = 0; y < scan_lines; ) {
  314.         /* copy slice to row buffer */
  315.         if (y > scan_lines - yslice)
  316.         lines = scan_lines - y;
  317.         else
  318.         lines = yslice;
  319.         for (i=0; i<lines; i++)
  320.             gdev_prn_copy_scan_lines(pdev, y+i, 
  321.             row + (bmp_raster*(lines-1-i)), raster);
  322.         SetDIBitsToDevice(wdev->hdcprn, 0, y, pdev->width, lines,
  323.         0, 0, 0, lines,
  324.         row,
  325.         (BITMAPINFO FAR *)&bmi, DIB_RGB_COLORS);
  326.         y += lines;
  327.  
  328.         /* inform user of progress */
  329.         sprintf(dlgtext, "%d%% done", (int)(y * 100L / scan_lines));
  330.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), dlgtext);
  331.         /* process message loop */
  332.         while (PeekMessage(&msg, hDlgModeless, 0, 0, PM_REMOVE)) {
  333.         if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  334.             TranslateMessage(&msg);
  335.             DispatchMessage(&msg);
  336.         }
  337.         }
  338.         if (hDlgModeless == 0) {
  339.             /* user pressed cancel button */
  340.         break;
  341.         }
  342.     }
  343.  
  344.     if (hDlgModeless == 0)
  345.         code = gs_error_Fatal;    /* exit Ghostscript cleanly */
  346.     else {
  347.         /* push out the page */
  348.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), "Ejecting page...");
  349.         Escape(wdev->hdcprn,NEWFRAME,0,NULL,NULL);
  350.         ShowWindow(hDlgModeless, SW_HIDE);
  351.     }
  352.  
  353. bmp_done:
  354.     GlobalUnlock(hrow);
  355.     GlobalFree(hrow);
  356.  
  357.     return code;
  358. }
  359.  
  360. /* combined color mappers */
  361.  
  362. /* 24-bit color mappers (taken from gdevmem2.c). */
  363. /* Note that Windows expects RGB values in the order B,G,R. */
  364.  
  365. /* Map a r-g-b color to a color index. */
  366. private gx_color_index
  367. win_pr2_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
  368.   gx_color_value b)
  369. {
  370.     switch(dev->color_info.depth) {
  371.       case 1:
  372.     return gdev_prn_map_rgb_color(dev, r, g, b);
  373.       case 4:
  374.     /* use only 8 colors */
  375.     return  (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
  376.              (g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
  377.              (b > (gx_max_color_value / 2 + 1) ? 1 : 0) ;
  378.       case 8:
  379.     return pc_8bit_map_rgb_color(dev, r, g, b);
  380.       case 24:
  381.     return gx_color_value_to_byte(r) +
  382.            ((uint)gx_color_value_to_byte(g) << 8) +
  383.            ((ulong)gx_color_value_to_byte(b) << 16);
  384.     }
  385.     return 0; /* error */
  386. }
  387.  
  388. /* Map a color index to a r-g-b color. */
  389. private int
  390. win_pr2_map_color_rgb(gx_device *dev, gx_color_index color,
  391.   gx_color_value prgb[3])
  392. {
  393.     switch(dev->color_info.depth) {
  394.       case 1:
  395.     gdev_prn_map_color_rgb(dev, color, prgb);
  396.     break;
  397.       case 4:
  398.     /* use only 8 colors */
  399.     prgb[0] = (color & 4) ? gx_max_color_value : 0;
  400.     prgb[1] = (color & 2) ? gx_max_color_value : 0;
  401.     prgb[2] = (color & 1) ? gx_max_color_value : 0;
  402.     break;
  403.       case 8:
  404.     pc_8bit_map_color_rgb(dev, color, prgb);
  405.     break;
  406.       case 24:
  407.     prgb[2] = gx_color_value_from_byte(color >> 16);
  408.     prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
  409.     prgb[0] = gx_color_value_from_byte(color & 0xff);
  410.     break;
  411.     }
  412.     return 0;
  413. }
  414.  
  415. void
  416. win_pr2_set_bpp(gx_device *dev, int depth)
  417. {
  418.     if (depth > 8) {
  419.         static const gx_device_color_info win_pr2_24color = dci_std_color(24);
  420.         dev->color_info = win_pr2_24color;
  421.     }
  422.     else if ( depth >= 8 ) {
  423.         /* 8-bit (SuperVGA-style) color. */
  424.         /* (Uses a fixed palette of 3,3,2 bits.) */
  425.         static const gx_device_color_info win_pr2_8color = dci_pc_8bit;
  426.         dev->color_info = win_pr2_8color;
  427.     }
  428.     else if ( depth >= 3) {
  429.         /* 3 plane printer */
  430.         /* suitable for impact dot matrix CMYK printers */
  431.         /* create 4-bit bitmap, but only use 8 colors */
  432.         static const gx_device_color_info win_pr2_4color = {3, 4, 1, 1, 2, 2};
  433.         dev->color_info = win_pr2_4color;
  434.     }
  435.     else {   /* default is black_and_white */
  436.         static const gx_device_color_info win_pr2_1color = dci_std_color(1);
  437.         dev->color_info = win_pr2_1color;
  438.     }
  439. }
  440.  
  441.  
  442. /* We implement this ourselves so that we can change BitsPerPixel */
  443. /* before the device is opened */
  444. int
  445. win_pr2_put_params(gx_device *dev, gs_param_list *plist)
  446. {    int ecode = 0, code;
  447.     int old_bpp = dev->color_info.depth;
  448.     int bpp = old_bpp;
  449.  
  450.     switch ( code = param_read_int(plist, "BitsPerPixel", &bpp) )
  451.     {
  452.     case 0:
  453.         if ( dev->is_open )
  454.           ecode = gs_error_rangecheck;
  455.         else
  456.           {    /* change dev->color_info is valid before device is opened */
  457.             win_pr2_set_bpp(dev, bpp);
  458.             break;
  459.           }
  460.         goto bppe;
  461.     default:
  462.         ecode = code;
  463. bppe:        param_signal_error(plist, "BitsPerPixel", ecode);
  464.     case 1:
  465.         break;
  466.     }
  467.  
  468.     if ( ecode >= 0 )
  469.         ecode = gdev_prn_put_params(dev, plist);
  470.     return ecode;
  471. }
  472.  
  473. #undef wdev
  474.  
  475. #ifndef __WIN32__
  476. #include <print.h>
  477. #endif
  478.  
  479.  
  480. /* Get Device Context for printer */
  481. private int
  482. win_pr2_getdc(gx_device_win_pr2 *wdev)
  483. {
  484. char *device;
  485. char *devices;
  486. char *p;
  487. char driverbuf[512];
  488. char *driver;
  489. char *output;
  490. char *devcap;
  491. int devcapsize;
  492. int size;
  493.  
  494. int i, n;
  495. POINT *pp;
  496. int paperindex;
  497. int paperwidth, paperheight;
  498. int orientation;
  499. int papersize;
  500. char papername[64];
  501. char drvname[32];
  502. HINSTANCE hlib;
  503. LPFNDEVMODE pfnExtDeviceMode;
  504. LPFNDEVCAPS pfnDeviceCapabilities;
  505. LPDEVMODE podevmode, pidevmode;
  506.  
  507. #ifdef __WIN32__
  508. HANDLE hprinter;
  509. #endif
  510.  
  511.  
  512.     /* first try to derive the printer name from -sOutputFile= */
  513.     /* is printer if name prefixed by \\spool\ */
  514.     if ( is_spool(wdev->fname) )
  515.     device = wdev->fname + 8;   /* skip over \\spool\ */
  516.     else
  517.     return FALSE;
  518.  
  519.     /* now try to match the printer name against the [Devices] section */
  520.     if ( (devices = gs_malloc(4096, 1, "win_pr2_getdc")) == (char *)NULL )
  521.     return FALSE;
  522.     GetProfileString("Devices", NULL, "", devices, 4096);
  523.     p = devices;
  524.     while (*p) {
  525.     if (strcmp(p, device) == 0)
  526.         break;
  527.     p += strlen(p) + 1;
  528.     }
  529.     if (*p == '\0')
  530.     p = NULL;
  531.     gs_free(devices, 4096, 1, "win_pr2_getdc");
  532.     if (p == NULL)
  533.     return FALSE;    /* doesn't match an available printer */
  534.  
  535.     /* the printer exists, get the remaining information from win.ini */
  536.     GetProfileString("Devices", device, "", driverbuf, sizeof(driverbuf));
  537.     driver = strtok(driverbuf, ",");
  538.     output = strtok(NULL, ",");
  539. #ifdef __WIN32__
  540.     if (is_win32s)
  541. #endif
  542.     {
  543.     strcpy(drvname, driver);
  544.     strcat(drvname, ".drv");
  545.     driver = drvname;
  546.     }
  547.  
  548.  
  549. #ifdef __WIN32__
  550.  
  551.     if (!is_win32s) {
  552.     if (!OpenPrinter(device, &hprinter, NULL))
  553.         return FALSE;
  554.     size = DocumentProperties(NULL, hprinter, device, NULL, NULL, 0);
  555.     if ( (podevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
  556.         ClosePrinter(hprinter);
  557.         return FALSE;
  558.     }
  559.     if ( (pidevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
  560.         gs_free(podevmode, size, 1, "win_pr2_getdc");
  561.         ClosePrinter(hprinter);
  562.         return FALSE;
  563.     }
  564.     DocumentProperties(NULL, hprinter, device, podevmode, NULL, DM_OUT_BUFFER);
  565.     pfnDeviceCapabilities = (LPFNDEVCAPS)DeviceCapabilities;
  566.     } else 
  567. #endif
  568.     {  /* Win16 and Win32s */
  569.     /* now load the printer driver */
  570.     hlib = LoadLibrary(driver);
  571.     if (hlib < (HINSTANCE)HINSTANCE_ERROR)
  572.         return FALSE;
  573.  
  574.     /* call ExtDeviceMode() to get default parameters */
  575.     pfnExtDeviceMode = (LPFNDEVMODE)GetProcAddress(hlib, "ExtDeviceMode");
  576.     if (pfnExtDeviceMode == (LPFNDEVMODE)NULL) {
  577.         FreeLibrary(hlib);
  578.         return FALSE;
  579.     }
  580.     pfnDeviceCapabilities = (LPFNDEVCAPS)GetProcAddress(hlib, "DeviceCapabilities");
  581.     if (pfnDeviceCapabilities == (LPFNDEVCAPS)NULL) {
  582.         FreeLibrary(hlib);
  583.         return FALSE;
  584.     }
  585.     size = pfnExtDeviceMode(NULL, hlib, NULL, device, output, NULL, NULL, 0);
  586.     if ( (podevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
  587.         FreeLibrary(hlib);
  588.         return FALSE;
  589.     }
  590.     if ( (pidevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
  591.         gs_free(podevmode, size, 1, "win_pr2_getdc");
  592.         FreeLibrary(hlib);
  593.         return FALSE;
  594.     }
  595.     pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
  596.         NULL, NULL, DM_OUT_BUFFER);
  597.     }
  598.  
  599.     /* now find out what paper sizes are available */
  600.     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, NULL, NULL);
  601.     devcapsize *= sizeof(POINT);
  602.     if ( (devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
  603.         return FALSE;
  604.     n = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, devcap, NULL);
  605.     paperwidth = wdev->MediaSize[0] * 254 / 72; 
  606.     paperheight = wdev->MediaSize[1] * 254 / 72; 
  607.     papername[0] = '\0';
  608.     papersize = 0;
  609.     paperindex = -1;
  610.     orientation = DMORIENT_PORTRAIT;
  611.     pp = (POINT *)devcap;
  612.     for (i=0; i<n; i++, pp++) {
  613.     if ( (pp->x < paperwidth + 20) && (pp->x > paperwidth - 20) &&
  614.          (pp->y < paperheight + 20) && (pp->y > paperheight - 20) ) {
  615.         paperindex = i;
  616.         paperwidth = pp->x;
  617.         paperheight = pp->y;
  618.         break;
  619.     }
  620.     }
  621.     if (paperindex < 0) {
  622.     /* try again in landscape */
  623.         pp = (POINT *)devcap;
  624.     for (i=0; i<n; i++, pp++) {
  625.         if ( (pp->x < paperheight + 20) && (pp->x > paperheight - 20) &&
  626.          (pp->y < paperwidth + 20) && (pp->y > paperwidth - 20) ) {
  627.         paperindex = i;
  628.         paperwidth = pp->x;
  629.         paperheight = pp->y;
  630.         orientation = DMORIENT_LANDSCAPE;
  631.         break;
  632.         }
  633.     }
  634.     }
  635.     gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
  636.  
  637.     /* get the dmPaperSize */
  638.     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERS, NULL, NULL);
  639.     devcapsize *= sizeof(WORD);
  640.     if ( (devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
  641.         return FALSE;
  642.     n = pfnDeviceCapabilities(device, output, DC_PAPERS, devcap, NULL);
  643.     if ( (paperindex >= 0) && (paperindex < n) )
  644.     papersize = ((WORD *)devcap)[paperindex];
  645.     gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
  646.  
  647.     /* get the paper name */
  648.     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, NULL, NULL);
  649.     devcapsize *= 64;
  650.     if ( (devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
  651.         return FALSE;
  652.     n = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, devcap, NULL);
  653.     if ( (paperindex >= 0) && (paperindex < n) )
  654.     strcpy(papername, devcap + paperindex*64);
  655.     gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
  656.     
  657.     memcpy(pidevmode, podevmode, size);
  658.  
  659.     pidevmode->dmFields = 0;
  660.  
  661.     pidevmode->dmFields |= DM_DEFAULTSOURCE;
  662.     pidevmode->dmDefaultSource = 0;
  663.  
  664.     pidevmode->dmFields |= DM_ORIENTATION;
  665.     pidevmode->dmOrientation = orientation;
  666.  
  667.     if (papersize)
  668.         pidevmode->dmFields |=  DM_PAPERSIZE;
  669.     else
  670.         pidevmode->dmFields &= (~DM_PAPERSIZE);
  671.     pidevmode->dmPaperSize = papersize;
  672.  
  673.     pidevmode->dmFields |=  (DM_PAPERLENGTH | DM_PAPERWIDTH);
  674.     pidevmode->dmPaperLength = paperheight;
  675.     pidevmode->dmPaperWidth = paperwidth;
  676.  
  677.  
  678. #ifdef WIN32
  679.     if (!is_win32s) {
  680.     /* change the page size by changing the form */
  681.     /* WinNT only */
  682.     /* Win95 returns FALSE to GetForm */
  683.     LPBYTE lpbForm;
  684.     FORM_INFO_1 *fi1;
  685.     DWORD dwBuf;
  686.     DWORD dwNeeded;
  687.     dwNeeded = 0;
  688.     dwBuf = 1024;
  689.         if ( (lpbForm = gs_malloc(dwBuf, 1, "win_pr2_getdc")) == (LPBYTE)NULL ) {
  690.         gs_free(podevmode, size, 1, "win_pr2_getdc");
  691.         gs_free(pidevmode, size, 1, "win_pr2_getdc");
  692.         ClosePrinter(hprinter);
  693.         return FALSE;
  694.     }
  695.     if (GetForm(hprinter, papername, 1, lpbForm, dwBuf, &dwNeeded)) {
  696.         fi1 = (FORM_INFO_1 *)lpbForm;
  697.         pidevmode->dmFields |= DM_FORMNAME;
  698.         SetForm(hprinter, papername, 1, (LPBYTE)fi1);
  699.     }
  700.     gs_free(lpbForm, dwBuf, 1, "win_pr2_getdc");
  701.  
  702.     strcpy(pidevmode->dmFormName, papername);
  703.     pidevmode->dmFields |= DM_FORMNAME;
  704.  
  705. /*
  706.     pidevmode->dmFields &= DM_FORMNAME;
  707.         pidevmode->dmDefaultSource = 0;
  708. */
  709.  
  710.     /* merge the entries */
  711.     DocumentProperties(NULL, hprinter, device, podevmode, pidevmode, DM_IN_BUFFER | DM_OUT_BUFFER);
  712.  
  713.     ClosePrinter(hprinter);
  714.     /* now get a DC */
  715.     wdev->hdcprn = CreateDC(driver, device, NULL, podevmode);
  716.     }
  717.     else 
  718. #endif
  719.     { /* Win16 and Win32s */
  720.     pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
  721.         pidevmode, NULL, DM_IN_BUFFER | DM_OUT_BUFFER);
  722.     /* release the printer driver */
  723.     FreeLibrary(hlib);
  724.     /* now get a DC */
  725.     if (is_win32s)
  726.         strtok(driver, ".");    /* remove .drv */
  727.     wdev->hdcprn = CreateDC(driver, device, output, podevmode);
  728.     }
  729.  
  730.     gs_free(pidevmode, size, 1, "win_pr2_getdc");
  731.     gs_free(podevmode, size, 1, "win_pr2_getdc");
  732.  
  733.     if (wdev->hdcprn != (HDC)NULL) 
  734.     return TRUE;    /* success */
  735.    
  736.     /* fall back to prompting user */
  737.     return FALSE;
  738. }
  739.